package fi.iki.joker.mobilogger;

import java.util.HashMap;
import java.util.LinkedList;

import android.R;
import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.text.Spannable;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.Spinner;
import android.widget.TextView;
import fi.iki.joker.mobilogger.blogs.BlogConfigConstants;
import fi.iki.joker.mobilogger.blogs.BlogInterface;
import fi.iki.joker.mobilogger.blogs.BlogInterfaceFactory;
import fi.iki.joker.mobilogger.db.BlogConfigBean;
import fi.iki.joker.mobilogger.db.BlogEntryBean;
import fi.iki.joker.mobilogger.db.DBUtil;
import fi.iki.joker.mobilogger.editor.SpannableBufferHelper;
import fi.iki.joker.mobilogger.util.AlertUtil;

/**
 * The PreviewDialog is the entrypoint to publishing, i.e. each entry to be published is previewed first. 
 * Also, the user is able to change the post's publish configuration from the publish dialog to make it easier to
 * post the same entry to many different blogs (TODO: why would one do this is a good question, so we need to follow up
 * whether it's actually used. If not let's remove that because it otherwise adds complexity without purpose. )
 * 
 * TODO: The thread communication (and progress dialog) implementation is not very clean nor efficient. It should be refactored
 * so that it would just use int codes in messages rather than sending the same information in Strings.  
 * @author juhak
 *
 */

public class PreviewDialog extends Activity implements AdapterView.OnItemSelectedListener,
	View.OnClickListener {

	private BlogEntryBean myEntryBean = null;
	//the handler for the UI callback from the publish thread
	final Handler mHandler = new Handler() {
		@Override
		public void handleMessage(Message msg) {
			Bundle content = msg.getData();
			String progressId = content.getString(MSG_KEY);
			if(progressId != null) {
				if(progressId.equals("1")) {
					publishProgress.setMessage("Preparing blog config...");
				} else if(progressId.equals("2")) {
					publishProgress.setMessage("Authenticating...");
				} else if(progressId.equals("3")) {
					publishProgress.setMessage("Contacting server...");
				} else if(progressId.equals("4")) {
					publishProgress.setMessage("Creating new entry...");
				} else if(progressId.equals("5")) {
					publishProgress.setMessage("Done...");
				}
			} else {
				// panic!
			}
		}
	};
	private final String MSG_KEY="value";
	private ProgressDialog publishProgress = null;
	HashMap<Integer, Integer> configItemOrder = null;
	int publishStatus = 0;
	private DBUtil db = null;
	int publishToConfigID = -1;
	final Runnable mPublishResults = new Runnable() {
		public void run () {
				showPublishedStatus();
		}
	};
	//Log.d(TAG,"Set position ["+curPosition+"]->"+order[position]);
	private final String TAG = "PreviewDialog";
	
	@Override
	protected void onCreate(Bundle icicle) {
		// TODO Auto-generated method stub
		super.onCreate(icicle);
		//NamespaceContextImpl nsi = new NamespaceContextImpl();
		setContentView(fi.iki.joker.mobilogger.R.layout.previewdialog);
		Spinner blogconfigs = (Spinner) findViewById(fi.iki.joker.mobilogger.R.id.blognamespinner);
		Button publishButton = (Button) findViewById(fi.iki.joker.mobilogger.R.id.publish_button);
		if(db == null) {
			db = new DBUtil();
		}
		LinkedList<BlogConfigBean> items = db.getBlogNames(this);
		//put the config item id numbers so that they can be looked up from the spinner indices
		//but the publishing. This is because if user changes the selection, we need to change
		//the config
		if(configItemOrder == null) {
			configItemOrder = new HashMap<Integer,Integer>(items.size());
		}
		for(int i=0; i<items.size();i++) {
			try {
				configItemOrder.put(new Integer(i), new Integer(items.get(i).getId()));
			} catch (NullPointerException ne) {
				Log.d(TAG,"Config items contains a null entry at "+i+"! Default to first config.");
				configItemOrder.put(new Integer(i), new Integer(0));
			}
		}
		Object res = new ArrayAdapter(this,android.R.layout.simple_spinner_item,items);
		ArrayAdapter<CharSequence> adapter = (ArrayAdapter<CharSequence>)res;
		adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
		blogconfigs.setAdapter(adapter);
		blogconfigs.setOnItemSelectedListener(this);
		publishButton.setOnClickListener(this);
		TextView content = (TextView) findViewById(fi.iki.joker.mobilogger.R.id.entrypreview);
		
		//get the selected values from the caller:
		Intent i = this.getIntent();
		if(i == null) {
			AlertUtil.showAlert(this,"Intent data missing!",
					"The intent used to launch this Activity was null!");
			this.finish();
		} else {
			Uri uri = i.getData();
			int entryid = -1;
			try {
				entryid = Integer.parseInt(uri.getLastPathSegment());
			} catch (NumberFormatException e) {
				AlertUtil.showAlert(this,"Intent data is invalid!",
						"The intent data used to launch this Activity cannot be parsed!");
				this.finish();
			}
			this.publishToConfigID = i.getIntExtra("fi.iki.joker.mobilogger.PublishConfigID", -1);
			if(this.publishToConfigID == -1) {
				AlertUtil.showAlert(this,"Intent data is invalid!",
						"The intent data (extra int) used to launch this Activity cannot be found!");
				this.finish();
			}
			//config id and blog entry id are now ok...
			this.myEntryBean = db.getBlogEntryById(this.getApplication(),entryid);
			if(this.myEntryBean == null) {
				AlertUtil.showAlert(this,"Intent data is invalid!", 
						"The intent data cannot be used to find the blog entry!");
			}
			//the "items" list has the id and name properties of 
			//blog configs. set the spinner's selected index to
			//be that index of the list which has "publishToConfigID"
			//in it's ID property.
			int selectedConfig = findListIndexOfConfig(items,this.publishToConfigID);
			if(selectedConfig != -1) {
				blogconfigs.setSelection(selectedConfig);
				this.myEntryBean.setPublishedIn(this.publishToConfigID);
			} else {
				AlertUtil.showAlert(this,"Intent data is invalid!",
						"The intent data (config ID) used to launch this Activity cannot be resolved to a config in database!");
				this.finish();
			}
		}
		
		content.append(myEntryBean.getTitle());
		content.append("\n");
		content.append(myEntryBean.getBlogEntry());	
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		// TODO Auto-generated method stub
		return super.onCreateOptionsMenu(menu);
	}

	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		// TODO Auto-generated method stub
		return super.onOptionsItemSelected(item);
	}
    
	public void onItemSelected(AdapterView parent, View v, int position, long id) {
		this.myEntryBean.setPublishedIn(position);
		publishToConfigID = configItemOrder.get(position);
    }

    public void onNothingSelected(AdapterView parent) {
    }

	public void onClick(View v) {
		this.publishBlogEntry();
	}
	

	private void publishBlogEntry() {
		final Activity thread_parent = this;
		publishProgress = ProgressDialog.show(this, "Publishing blog entry", "Starting to publish blog entry...");
		Thread publish = new Thread () {
			public void run() {
				Bundle status = new Bundle();
				mHandler.getLooper().prepare();
				Message statusMsg = mHandler.obtainMessage();
				publishStatus = 0;
				status.putString(MSG_KEY, "1");
				statusMsg.setData(status);
				mHandler.sendMessage(statusMsg);
				boolean publishOk = false;
				CheckBox draftCb = (CheckBox) findViewById(fi.iki.joker.mobilogger.R.id.blog_options_asdraftcheckbox);
				if(draftCb != null) {
					myEntryBean.setDraft(draftCb.isChecked());
				}
				//here we should read the blog config number, if it has been changed, from the preview
				//activity and change publish API and other details accordingly
				int confignum = publishToConfigID;
				if(db == null) {
					db = new DBUtil();
				}
				BlogConfigBean bc = null;
				if(db.isDatabaseReady(thread_parent)) {
					Log.d(TAG,"Database ready, get the id...");
					bc = db.getBlogConfigById(confignum);
				}
				BlogConfigConstants.BlogInterfaceType typeEnum = BlogConfigConstants.getInterfaceTypeByNumber(bc.getPostmethod());
				BlogInterface blogapi = null;
				blogapi = BlogInterfaceFactory.getInstance(typeEnum);
				Log.d(TAG,"Using interface type: "+typeEnum);
				Log.d(TAG,"Preparing the API with saved editor data: "+bc.getPostConfig());
				blogapi.setInstanceConfig(bc.getPostConfig());
				Log.d(TAG,"Trying to get auth token for config id: "+confignum+" with username "+bc.getUsername());
				status.putString(MSG_KEY, "2");
				statusMsg = mHandler.obtainMessage();
				statusMsg.setData(status);
				mHandler.sendMessage(statusMsg);
				String auth_id = blogapi.getAuthId(bc.getUsername(), bc.getPassword());
				publishStatus = 1;
				Log.d(TAG,"Got auth token:"+auth_id);
				publishStatus = 2;
				if(auth_id != null) {
				status.putString(MSG_KEY, "3");
				statusMsg = mHandler.obtainMessage();
				statusMsg.setData(status);
				mHandler.sendMessage(statusMsg);
				String postUri = blogapi.getPostUrl(auth_id);
				SpannableBufferHelper helper = new SpannableBufferHelper();
				status.putString(MSG_KEY, "4");
				statusMsg = mHandler.obtainMessage();
				statusMsg.setData(status);
				mHandler.sendMessage(statusMsg);
				publishOk = blogapi.createPost(thread_parent, auth_id, postUri, null, 
						myEntryBean.getTitle(), null, 
						helper.SpannableToXHTML((Spannable)(myEntryBean.getBlogEntry())), 
						bc.getUsername(), bc.getUsername(), myEntryBean.isDraft());
				} else {
					publishStatus = 3;	
				}
				status.putString(MSG_KEY, "5");
				statusMsg = mHandler.obtainMessage();
				statusMsg.setData(status);
				mHandler.sendMessage(statusMsg);
				if(publishOk) {
					Log.d(TAG,"Post published successfully!");
					publishStatus = 5;
				} else {
					Log.d(TAG,"Publishing of the post failed!");
					publishStatus = 4;
				}
				mHandler.post(mPublishResults);
			}
		};	
		publish.start();
		publishProgress.setMessage("Started publishing...");
	}
	
	private void showPublishedStatus() {
		publishProgress.dismiss();
		if(publishStatus == 5) {
			AlertUtil.showAlert(this,"Publish status","Publish Ok!");
			// activity should finish after ok.
		} else {
			AlertUtil.showAlert(this,"Publish status","Publish failed! (Code "+publishStatus+")");
		}
	}
	
	private int findListIndexOfConfig(LinkedList<BlogConfigBean> items, int lookfor) {
		for(int i = 0; i < items.size();i++) {
			BlogConfigBean inspect = items.get(i);
			if(inspect != null) {
				if(inspect.getId() == lookfor) {
					return i;
				}
			} else {
				Log.e(TAG,"Received a null configBean from DB!");
				return -1;
			}
		}
		return -1;
	}
}